<template>
  <div class="sky_audio">
    <div class="slider_box u-f u-f-ac u-f-jsb">
      <span class="play_time">{{ playTime }}</span>
      <van-slider
        v-model="slider"
        inactive-color="var(--sky-text-gray4-color)"
        active-color="var(--sky-text-gray6-color)"
        :button-size="8"
        @change="onSliderChange"
      />
      <span class="all_time">{{ allTime }}</span>
    </div>
    <!--  -->
    <audio ref="audio">
      <source :src="audioUrl" type="audio/mpeg" />
    </audio>
    <div class="audio_box u-f u-f-ac u-f-jc">
      <!-- 播放模式 -->
      <div class="icon_box u-f u-f-ac u-f-jc">
        <i class="iconfont icon-xunhuan"></i>
      </div>
      <!-- 上一首 -->
      <div class="icon_box u-f u-f-ac u-f-jc" @click="prevSong">
        <i class="iconfont icon-shangyishou"></i>
      </div>
      <!-- 播放 | 暂停 -->
      <div class="icon_box u-f u-f-ac u-f-jc">
        <i
          class="iconfont icon-bofang4"
          @click="playAudio"
          v-show="!playOrPause || playOrPause === 'pause'"
        ></i>
        <i
          class="iconfont icon-pause"
          @click="pauseAudio"
          v-show="playOrPause === 'play'"
        ></i>
      </div>
      <!-- 下一首 -->
      <div class="icon_box u-f u-f-ac u-f-jc" @click="nextSong">
        <i class="iconfont icon-shangyishou1"></i>
      </div>
      <!-- 播放列表 -->
      <div class="icon_box u-f u-f-ac u-f-jc" @click="openPlayPopup">
        <i class="iconfont icon-caidan"></i>
      </div>
    </div>
  </div>
  <!-- 播放列表 -->
  <play-list-popup ref="showPlayList"></play-list-popup>
</template>

<script lang="ts">
import {
  computed,
  ComputedRef,
  defineComponent,
  onMounted,
  Ref,
  ref,
  watch,
} from 'vue'
import { formatTime } from '@/assets/ts/util'
import { Store, useStore } from 'vuex'
import { songUrl } from '@/api/play'
import PlayListPopup from '@/components/common/play-list-popup.vue'
import { Toast } from 'vant'

// 打开播放列表弹窗
const handlePlayPopup = () => {
  const showPlayList: Ref<any> = ref(null)

  const openPlayPopup = () => {
    showPlayList.value?.open()
  }

  return {
    showPlayList,
    openPlayPopup,
  }
}

// 控制音频
const handleChangeAudio = (
  context: any,
  audio: Ref<any>,
  duration: ComputedRef<number>
) => {
  const store = useStore()
  const slider: Ref<number> = ref(0)
  const playTime: Ref<string> = ref('00:00')

  const playAudio = () => {
    // 播放音频
    if (!audio.value) return
    audio.value
      .play()
      .then(() => {
        store.commit('setPlayOrPause', 'play')
        store.commit('setAudioObj', audio.value)
        store.commit('setIsFirstRun', false)
      })
      .catch(() => {
        // 播放错误时
        store.commit('setPlayOrPause', '')
      })
  }

  const pauseAudio = () => {
    // 暂停音频
    if (!audio.value) return
    audio.value.pause()
    store.commit('setPlayOrPause', 'pause')
  }

  const loadAudio = () => {
    // 重新加载音频元素
    if (!audio.value) return
    audio.value.load()
    store.commit('setPlayOrPause', '')
  }

  const audioEnd = () => {
    // 播放结束后执行的事件
    store.commit('setPlayOrPause', '')
    nextSong()
  }

  const updateSlider = () => {
    // 这个时间精度到秒，用于进度条显示
    const time = Math.floor(audio.value?.currentTime || 0)
    // 这个时间精度到毫秒，用于匹配歌词
    const lyricTime = audio.value?.currentTime
      ? Number(audio.value.currentTime.toFixed(1))
      : 0
    context.emit('changeLyricTime', lyricTime)
    playTime.value = formatTime(time)

    const b = (time / duration.value) * 100
    slider.value = Number(b.toFixed(1))
    store.commit('setAudioProgress', slider.value)
  }

  // 手动点击滑块
  const onSliderChange = (value: number) => {
    if (!audio.value.paused || audio.value.currentTime !== 0) {
      const time = Math.floor((duration.value * value) / 100)
      audio.value.currentTime = time
      playTime.value = formatTime(time)
    }
  }

  // 上一首
  const prevSong = () => {
    const list = store.state.playlist

    if (list.length <= 1) {
      return Toast('没有其他歌曲了')
    }

    store.commit('setAudioProgress', 0)

    let index = store.state.playIndex
    if (index === 0) {
      store.commit('setPlayIndex', list.length - 1)
      store.commit('setCurrentPlaying', list[list.length - 1])
    } else {
      store.commit('setPlayIndex', --index)
      store.commit('setCurrentPlaying', list[index])
    }
  }

  // 下一首
  const nextSong = () => {
    const list = store.state.playlist

    if (list.length <= 1) {
      if (audio.value.ended) {
        pauseAudio()
      }
      return Toast('没有其他歌曲了')
    }

    store.commit('setAudioProgress', 0)

    let index = store.state.playIndex
    if (index === list.length - 1) {
      store.commit('setPlayIndex', 0)
      store.commit('setCurrentPlaying', list[0])
    } else {
      store.commit('setPlayIndex', ++index)
      store.commit('setCurrentPlaying', list[index])
    }
  }

  onMounted(() => {
    if (audio.value.paused) {
      // 处理因意外停止播放，再次进入时
      pauseAudio()
    }
    audio.value.addEventListener('ended', () => {
      // 监听播放结束
      audioEnd()
    })
    audio.value.addEventListener('timeupdate', () => {
      // 监听播放位置发生改变
      updateSlider()
    })
  })

  return {
    slider,
    playTime,
    onSliderChange,
    playAudio,
    pauseAudio,
    loadAudio,
    prevSong,
    nextSong,
  }
}

// 获取音乐url
const handleSongUrl = (store: Store<any>, playAudio: any, loadAudio: any) => {
  const audioUrl: Ref<string> = ref('')

  const getSongUrl = async () => {
    const { data } = await songUrl(store.state.currentPlaying?.id)

    audioUrl.value = data.data[0].url

    loadAudio()
    if (!store.state.isFirstRun) {
      playAudio()
    }
  }

  watch(
    () => store.state.currentPlaying,
    (newVal) => {
      if (newVal.id) {
        getSongUrl()
      }
    },
    {
      immediate: true,
    }
  )

  return {
    audioUrl,
    getSongUrl,
  }
}

export default defineComponent({
  name: 'SkyAudio',
  props: {
    time: {
      type: Number,
      default: 0,
    },
  },
  emits: ['changeLyricTime'],
  components: {
    PlayListPopup,
  },
  setup(props, context) {
    const store = useStore()
    const audio: Ref<any> = ref(null)
    const duration = computed(() => {
      return props.time
    })
    const allTime = computed(() => {
      return formatTime(props.time)
    })

    const playOrPause = computed(() => {
      return store.state.playOrPause
    })

    const {
      slider,
      playTime,
      playAudio,
      pauseAudio,
      loadAudio,
      onSliderChange,
      prevSong,
      nextSong,
    } = handleChangeAudio(context, audio, duration)

    const { audioUrl, getSongUrl } = handleSongUrl(store, playAudio, loadAudio)

    const { showPlayList, openPlayPopup } = handlePlayPopup()

    return {
      slider,
      audio,
      playTime,
      allTime,
      playOrPause,
      audioUrl,
      duration,
      showPlayList,
      onSliderChange,
      playAudio,
      pauseAudio,
      loadAudio,
      prevSong,
      nextSong,
      getSongUrl,
      openPlayPopup,
    }
  },
})
</script>

<style lang="less" scoped>
.sky_audio {
  .slider_box {
    height: 30px;
    padding: 0 16px;
    .play_time {
      display: inline-block;
      font-size: 14px;
      color: var(--sky-text-white-color);
      margin-right: 10px;
    }
    .all_time {
      display: inline-block;
      font-size: 14px;
      color: var(--sky-text-white-color);
      margin-left: 10px;
    }
  }
  .audio_box {
    height: 65px;
    .icon_box {
      width: 65px;
      .iconfont {
        font-size: 20px;
        color: var(--sky-text-white-color);
        &.icon-bofang4,
        &.icon-pause {
          font-size: 46px;
        }
      }
    }
  }
}
</style>